﻿using System;
using System.Collections.Generic;
using System.Linq;
using CCodeTreeLib;
using SqlOrm.Xml;

namespace SqlOrm.TreeBuilders
{
    public class ServiceContractTreeBuilder : CCodeTree
    {
        DataDictionary _ddl;
        bool _messagecontracts = true;
        SqlContextTreeBuilder _context;

        public ServiceContractTreeBuilder(DataDictionary ddl, SqlContextTreeBuilder context)
        {
            _ddl = ddl;
            _context = context;
            BuildServiceContracts();
        }

        private void BuildServiceContracts()
        {
            var ns = AddStatement(new CCodeNamespace(_ddl.Settings.ServiceContractOutput.clrnamespace));
            Usings.Add(new CCodeUsing("System"));
            Usings.Add(new CCodeUsing("System.Net.Security"));
            Usings.Add(new CCodeUsing("System.ServiceModel"));

            if (_ddl.Settings.ServiceContractOutput.clrnamespace != _ddl.Settings.DataContractOutput.clrnamespace)
                Usings.Add(new CCodeUsing(_ddl.Settings.DataContractOutput.clrnamespace));
            Usings.Add(new CCodeUsing("System.Collections.Generic"));

            var c = new CCodeClass(_ddl.Settings.BusinessOutput.@class);

            var si = new CCodeInterface(string.Format("I{0}", _ddl.Settings.BusinessOutput.@class));
            si.Modifier = Modifier.Public;
            
            ns.AddInterface(si);
            si.Attributes.Add(new CCodeAttribute("ServiceContract", string.Format("Namespace = \"{0}\",  SessionMode = SessionMode.Allowed, ProtectionLevel = ProtectionLevel.None ", _ddl.Settings.ServiceContractOutput.urinamespace)));

            var methods = _context.OfType<CCodeMethod>();
            foreach (var method in methods)
            {
                
            }

            //BuildAlls(si);
            //BuildDeletes(si);
            //BuildGets(si);
            //BuildProcs(si);
            //BuildSearches(si);
            //BuildUpserts(si);
        }

        private void BuildSearches(CCodeInterface si)
        {
            foreach (var table in _ddl.Definition.Schema.Table.Where(x => !string.IsNullOrEmpty(x.search)))
            {
                string[] patterns = table.search.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var pattern in patterns)
                {

                    string[] sname = pattern.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    var searchFields = new List<Field>();
                    foreach (var s in sname)
                    {
                        Field f = table.Field.Where(x => x.name == s).FirstOrDefault();
                        if (f != null)
                            searchFields.Add(f);
                    }
                    string procArgsName = string.Empty;
                    Array.ForEach(searchFields.ToArray(), x => procArgsName += x.title);
                    string methodName = string.Format("Search{0}By{1}", table.name, procArgsName);

                    
                    string returnType = string.Empty;
                    if (_messagecontracts)
                        returnType = methodName + "Response";
                    else
                        returnType = "List<" + table.name + ">";

                    var sm = si.AddMember(new CCodeMethod(returnType, methodName));
                    sm.Attributes.Add(new CCodeAttribute("OperationContract", string.Format("IsTerminating = false, IsInitiating = true, IsOneWay = false, AsyncPattern = false, Action = \"{0}/{1}\", ProtectionLevel = ProtectionLevel.None", _ddl.Settings.ServiceContractOutput.urinamespace, methodName)));

                    if (_messagecontracts)
                    {
                        sm.Parameters.Add(new CCodeField(methodName + "Request", table.name.ToLower() + "Request"));
                    }
                    else
                    {
                        foreach (var s in searchFields)
                        {
                            sm.Parameters.Add(new CCodeField(s.ClrDataType, s.name));
                        }
                    }
                }
            }
        }

        private void BuildUpserts(CCodeInterface si)
        {
            foreach (var table in _ddl.Definition.Schema.Table)
            {
                string returnType = "void";// table.name;
                if (_messagecontracts)
                    returnType = "Upsert" + table.name + "Response";
                var sm = si.AddMember(new CCodeMethod(returnType, "Upsert" + table.name));
                sm.Attributes.Add(new CCodeAttribute("OperationContract", string.Format("IsTerminating = false, IsInitiating = true, IsOneWay = false, AsyncPattern = false, Action = \"{0}/{1}\", ProtectionLevel = ProtectionLevel.None", _ddl.Settings.ServiceContractOutput.urinamespace, "Upsert" + table.name)));
                if (_messagecontracts)
                {
                    sm.Parameters.Add(new CCodeField("Upsert" + table.name + "Request", table.name.ToLower() + "Request"));
                }
                else
                {
                    //foreach (var f in table.Field.Where(x => x.key))
                    //    sm.Parameters.Add(new CCodeField(f.ClrDataType, f.name));
                    sm.Parameters.Add(new CCodeField(table.name, table.name.ToLower()));
                }
            }
        }

        private void BuildProcs(CCodeInterface si)
        {
            if (_ddl.Definition.Procedures != null)
            {
                foreach (var proc in _ddl.Definition.Procedures)
                {
                    string returnType = string.Empty;
                    if (_messagecontracts)
                        returnType = proc.name + "Response";
                    else
                    {
                        if (proc.Input != null && proc.Input.Count() > 0)
                            returnType = "List<" + proc.name + "Output" + ">";
                        else
                            returnType = "void";
                    }
                    var sm = si.AddMember(new CCodeMethod(returnType, proc.name));
                    sm.Attributes.Add(new CCodeAttribute("OperationContract", string.Format("IsTerminating = false, IsInitiating = true, IsOneWay = false, AsyncPattern = false, Action = \"{0}/{1}\", ProtectionLevel = ProtectionLevel.None", _ddl.Settings.ServiceContractOutput.urinamespace, proc.name)));
                    if (_messagecontracts)
                    {
                        sm.Parameters.Add(new CCodeField(proc.name + "Request", proc.name.ToLower() + "Request"));
                    }
                    else
                    {
                        if (proc.Input != null)
                        {
                            foreach (var f in proc.Input)
                                sm.Parameters.Add(new CCodeField(f.ClrDataType, f.name));
                        }
                    }
                }
            }
        }

        private void BuildAlls(CCodeInterface si)
        {
            foreach (var table in _ddl.Definition.Schema.Table.Where(x=>x.all))
            {
                string returnType = "List<" + table.name + ">";
                if (_messagecontracts)
                    returnType = "All" + table.name + "Response";
                var sm = si.AddMember(new CCodeMethod(returnType, "All" + table.name));
                sm.Attributes.Add(new CCodeAttribute("OperationContract", string.Format("IsTerminating = false, IsInitiating = true, IsOneWay = false, AsyncPattern = false, Action = \"{0}/{1}\", ProtectionLevel = ProtectionLevel.None", _ddl.Settings.ServiceContractOutput.urinamespace, "All" + table.name)));
                if (_messagecontracts)
                {
                    sm.Parameters.Add(new CCodeField("All" + table.name + "Request", table.name.ToLower() + "Request"));
                }
                //else
                //{
                //    foreach (var f in table.Field.Where(x => x.key))
                //        sm.Parameters.Add(new CCodeField(f.ClrDataType, f.name));
                //}
            }
        }

        private void BuildDeletes(CCodeInterface si)
        {
            foreach (var table in _ddl.Definition.Schema.Table.Where(x=>x.delete))
            {
                string returnType = "void";// table.name;
                if (_messagecontracts)
                    returnType = "Delete" + table.name + "Response";
                var sm = si.AddMember(new CCodeMethod(returnType, "Delete" + table.name));
                sm.Attributes.Add(new CCodeAttribute("OperationContract", string.Format("IsTerminating = false, IsInitiating = true, IsOneWay = false, AsyncPattern = false, Action = \"{0}/{1}\", ProtectionLevel = ProtectionLevel.None", _ddl.Settings.ServiceContractOutput.urinamespace, "Delete" + table.name)));
                if (_messagecontracts)
                {
                    sm.Parameters.Add(new CCodeField("Delete" + table.name + "Request", table.name.ToLower() + "Request"));
                }
                else
                {
                    foreach (var f in table.Field.Where(x => x.key))
                        sm.Parameters.Add(new CCodeField(f.ClrDataType, f.name));
                }
            }
        }

        private void BuildGets(CCodeInterface si)
        {
            foreach (var table in _ddl.Definition.Schema.Table)
            {
                string returnType = table.name;
                if (_messagecontracts)
                    returnType = "Get" + table.name +  "Response";
                var sm = si.AddMember(new CCodeMethod(returnType, "Get" + table.name));
                sm.Attributes.Add(new CCodeAttribute("OperationContract", string.Format("IsTerminating = false, IsInitiating = true, IsOneWay = false, AsyncPattern = false, Action = \"{0}/{1}\", ProtectionLevel = ProtectionLevel.None", _ddl.Settings.ServiceContractOutput.urinamespace, "Get" + table.name)));
                if (_messagecontracts)
                {
                    sm.Parameters.Add(new CCodeField("Get" + table.name + "Request", table.name.ToLower() + "Request"));
                }
                else
                {
                    foreach (var f in table.Field.Where(x => x.key))
                        sm.Parameters.Add(new CCodeField(f.ClrDataType, f.name));
                }
            }
        }

    }
}
